// 导入 axios 模块
import axios from 'axios'
// 导入 store 模块
import store from '@/store'
// 导入更新token的接口函数
import { updateTokenAPI } from '@/api/user'
// 导入 router 模块
import router from '@/router'

// 导入 轻提示 函数
import { Toast } from 'vant'

// 创建 axios 实例
const instance = axios.create({
  // 1. 配置基地址
  baseURL: 'https://toutiao.itheima.net',
  // 2. 请求超时时间
  timeout: 5000
})

// 请求拦截器
instance.interceptors.request.use((config) => {
  // 这里的config就是请求对象，包含了此时请求的所用信息
  // 例如：method，url，data，params，headers等
  // 统一携带token给后台
  const { token } = store.state.user
  // 如果有token
  if (token) {
    // 给请求头添加 Authorization 属性，把登录成功的token发给服务器
    config.headers.Authorization = `Bearer ${token}`
  }
  // 必须返回config，这样请求信息才能达到服务器，否则请求会失败
  return config
}, (error) => {
  return Promise.reject(error)
})

// 响应拦截器
// 服务器在把数据给接口函数之前必须经过这一道关卡
// 可以在响应拦截器中对响应做公共处理
instance.interceptors.response.use((resp) => {
  // 成功的回调，当http状态码以2或3开头都会走这里
  // 响应成功了，直接把data数据返回给接口函数调用的地方
  // 这样接口函数拿到的数据就可以少写一层 .data
  // 这个操作可以称为剥离响应无效数据
  return resp.data
}, async (error) => {
  if (error.response.status === 401) { // token过期了
    // 情况1：token过期了，但refreshToken未过期
    // 1. 当token过期了，在响应拦截器中统一处理
    // 2. 通过refreshToken去获取一个新的token（refreshToken有效期比token长）
    try {
      // 无感知刷新token
      const resp = await updateTokenAPI()
      // 3. 用新的token去更新旧vuex中的token（提交vuex中的setToken函数）
      store.commit('user/setToken', resp.data.data.token)
      // 4. 用得到的新的token继续之前未遂的请求
      // 继续调用request发请求，error.config获取的请求失败接口的所有请求信息
      // 这里必须添加return，把请求结果返回给接口调用的地方
      return instance(error.config)
      // 或调用axios发请求，只是代码量多一些
      // return axios({
      //   ...error.config,
      //   url: `https://toutiao.itheima.net${error.config.url}`,
      //   headers: {
      //     Authorization: `Bearer ${resp.data.data.token}`
      //   }
      // })
    } catch (err) {
      // 情况2：token过期了，并且refreshToken也过期了
      // 代码走到这里了，说明 refreshToken 也过期了
      if (err.response.data.message === 'refresh_token失效') { // refreshToken过期，重新登录
        // 有感知刷新token
        // 给个登录过期的提示
        Toast('登录过期、请重新登录')
        // 清空vuex中的token和refreshToken
        store.dispatch('user/loginAction')
        // $route: 当前激活的路由的对象（在组件中用）
        // router.currentRoute: 当前激活的路由的对象（在js模块中用）
        // 跳转至登录页，并携带回跳地址
        router.push(`/login?redirectUrl=${router.currentRoute.path}`)
      }
    }
  }
  // 失败的回调，当http状态码以4或5开头都会走这里
  // todo：token过期处理
  return Promise.reject(error)
})

// 导入请求实例
export default instance

// token续签的思路：
// 前提：有很多接口发给服务器的时候(请求拦截器中统一携带），需要携带token，
//      但如果发给服务器的token是一个过期的，此次请求会失败，服务器会响应401状态码
// 1. 当token过期了，在响应拦截器中统一处理
// 2. 通过refreshToken去获取一个新的token（refreshToken有效期比token长）
// 3. 用得到的新的token继续之前未遂的请求
